package com.sicent.operate.common.droppoint;


import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang.StringUtils;

import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

public class HashAlgorithmUtil {

	public static final Integer EXE_TIMES = 100000000; 
	
	public static final Integer TABLE_NODE_COUNT;
	
	public static final Integer REDIS_NODE_COUNT;
	
	public static List<String> userInfoNodes;
	
	public static List<String> userAccountNodes;
	
	public static List<String> barUserNodes;
	
	public static List<String> lolGameRoleTableNodes;
	
	public static List<String> lolRankListTables;

	public static List<String> lolScoreFlowTables;

	public static List<String> lolScoreBarUserTables;
	
	public static Map<String, String> dataSourceNodeMap;
	
	public static List<JedisPool> redisServerNodes;
	
	private static DecimalFormat format = new DecimalFormat("00");
	
	private static ResourceBundle bundle;
	
	static {
		REDIS_NODE_COUNT = 1;
		TABLE_NODE_COUNT = 256;
		userInfoNodes = new ArrayList<String>();
		userAccountNodes = new ArrayList<String>();
		barUserNodes = new ArrayList<String>();
		lolGameRoleTableNodes= new ArrayList<String>();
		lolRankListTables = new ArrayList<String>();
		lolScoreFlowTables = new ArrayList<String>();
		lolScoreBarUserTables = new ArrayList<String>();
		for (int i = 0; i < TABLE_NODE_COUNT; i++) {
			userInfoNodes.add("user_info_" + getCounter(i));
			userAccountNodes.add("user_account_" + getCounter(i));
			barUserNodes.add("bar_user_" + getCounter(i));
			lolGameRoleTableNodes.add("lol_game_role_"+getCounter(i));
			lolRankListTables.add("lol_rank_list_" + getCounter(i));
			lolScoreFlowTables.add("score_flow_"+getCounter(i));
			lolScoreBarUserTables.add("score_bar_user_"+getCounter(i));
		}
		
		dataSourceNodeMap = new HashMap<String, String>();
		for(int i = 1; i <= 8; i++){
			dataSourceNodeMap.put(i+"_"+1, "dataSource"+i+"_"+1);
			dataSourceNodeMap.put(i+"_"+8, "dataSource"+i+"_"+8);
			dataSourceNodeMap.put(i+"_"+3, "dataSource"+i+"_"+3);
			dataSourceNodeMap.put(i+"_"+9, "dataSource"+i+"_"+9);
			dataSourceNodeMap.put(i+"_"+10, "dataSource"+i+"_"+10);
		}
		
		dataSourceNodeMap.put("baseDataSource", "baseDataSource");
		dataSourceNodeMap.put("appDataSourceNoTransaction", "appDataSourceNoTransaction");
		dataSourceNodeMap.put("lolDataSource", "lolDataSource");
		bundle = ResourceBundle.getBundle("config/redis");
		redisServerNodes = new ArrayList<JedisPool>();
		JedisPoolConfig config = new JedisPoolConfig();
		config.setMaxTotal(Integer.valueOf(bundle.getString("redis.pool.maxActive")));
		config.setMaxIdle(Integer.valueOf(bundle.getString("redis.pool.maxIdle")));
		config.setMaxWaitMillis(Long.valueOf(bundle.getString("redis.pool.maxWait")));
		config.setTestOnBorrow(Boolean.valueOf(bundle.getString("redis.pool.testOnBorrow")));
		config.setTestOnReturn(Boolean.valueOf(bundle.getString("redis.pool.testOnReturn")));
		JedisPool pool = new JedisPool(config, bundle.getString("base.redis.ip").trim(),Integer.valueOf(bundle.getString("base.redis.port").trim()));
		redisServerNodes.add(pool);
	}
	
	public static String getCounter(int i){
		String counter = null;
		if(i < 10){
			 counter = format.format(Long.valueOf(Integer.toHexString(i)));
		}else{
			counter = Integer.toHexString(i);
			if (counter.length() == 1) {
				counter = "0" + counter;
			}
		}
		return counter;
	}
	
	
	public static String hashTable(String account, TableType tableType){
		if (tableType == TableType.USER_INFO) { 
			return userInfoNodes.get(stringToHex(first2Bit(account)) % TABLE_NODE_COUNT);
		} else if (tableType == TableType.BAR_USER) {
			return barUserNodes.get(stringToHex(first2Bit(account)) % TABLE_NODE_COUNT);
		} else {
			return userAccountNodes.get(stringToHex(first2Bit(account)) % TABLE_NODE_COUNT);
		}
	}
	
	public static String hashDataSourceBySnbid(String snbid, TableType tableType){
		int dataSourceIndex = getDataSourceIndex(first2Bit(snbid.toLowerCase()));
		return dataSourceNodeMap.get(dataSourceIndex + "_" + tableType.getTableType());
	}
	
	public static String hashDataSourceByAccount(String account, TableType tableType){
		int dataSourceIndex = getDataSourceIndex(first2Bit(account));
		return dataSourceNodeMap.get(dataSourceIndex+"_" + tableType.getTableType());
	}
	
	public static String hashDataSourceByAccount(Integer account, TableType tableType){
		return hashDataSourceByAccount(String.valueOf(account), tableType);
	}
	
	public static String hashDataSourceByUserId(String userId, TableType tableType){
		int dataSourceIndex = getDataSourceIndex(first2Bit(userId));
		return dataSourceNodeMap.get(dataSourceIndex + "_" + tableType.getTableType());
	}
	
	public static String hashLolGameRoleTable(String userId){
		return lolGameRoleTableNodes.get(stringToHex(first2Bit(userId)) % TABLE_NODE_COUNT);
	}
	
	public static String hashLolRankListRoleTable(String snbid) {
		return lolRankListTables.get(stringToHex(first2Bit(snbid.toLowerCase())) % TABLE_NODE_COUNT);
	}

	public static String hashLolScoreFlowTable(String snbid) {
		return lolScoreFlowTables.get(stringToHex(first2Bit(snbid.toLowerCase())) % TABLE_NODE_COUNT);
	}

	public static String hashLolScoreBarUserTable(String snbid) {
		return lolScoreBarUserTables.get(stringToHex(first2Bit(snbid.toLowerCase())) % TABLE_NODE_COUNT);
	}
	
	public static String getBaseDataSource(){
		return dataSourceNodeMap.get("baseDataSource");
	}
	
	public static String getLolDataSource(){
		return dataSourceNodeMap.get("lolDataSource");
	}
	
	public static String getAppDataSourceNoTransaction(){
		return dataSourceNodeMap.get("appDataSourceNoTransaction");
	}
	
	public static JedisPool hashRedisServer(String key){
		return redisServerNodes.get(0);
	}
	
	public static String first2Bit(String userId){
		return StringUtils.substring(DigestUtils.md5Hex(userId), 0, 2);
	}
	
	public static String second2Bit(String userId){
		return StringUtils.substring(DigestUtils.md5Hex(userId), 2, 4);
	}
	
	public static Integer stringToHex(String bit){
		return Integer.parseInt(bit, 16);
	}
	
	public static int getDataSourceIndex(String md5Bit){
		Integer index = stringToHex(md5Bit);
		if (index <=31) {
			return 1;
		} else if (index <= 63) {
			return 2;
		} else if (index <= 95) {
			return 3;
		} else if (index <= 127) {
			return 4;
		} else if (index <= 159) {
			return 5;
		} else if (index <= 191) {
			return 6;
		} else if (index <= 223) {
			return 7;
		} else if (index <= 255) {
			return 8;
		}
		throw new ArrayIndexOutOfBoundsException("dataSource Index out of bounds Exception");
	}
}
